
#include "app_hl.h"

static void _hl_log(int ret, const char *format, ...)
{
    char *msg = "";
    switch (ret)
    {
    case HL_ERROR_SUCCESSFUL:
        msg = "HL_ERROR_SUCCESSFUL 成功操作";
        break;
    case HL_ERROR_NO_INITIALIZED:
        msg = "HL_ERROR_NO_INITIALIZED 库未初始化";
        break;
    case HL_ERROR_ALREADY_INITIALIZED:
        msg = "HL_ERROR_ALREADY_INITIALIZED 已经初始化好了，不需要再初始化";
        break;
    case HL_ERROR_TIME_OUT:
        msg = "HL_ERROR_TIME_OUT 操作超时，可以重复操作";
        break;
    case HL_ERROR_INVALID_ID:
        msg = "HL_ERROR_INVALID_ID 无效DID";
        break;
    case HL_ERROR_INVALID_PARAMETER:
        msg = "HL_ERROR_INVALID_PARAMETER 无效参数";
        break;
    case HL_ERROR_DEVICE_NOT_ONLINE:
        msg = "HL_ERROR_DEVICE_NOT_ONLINE 设备不在线";
        break;
    case HL_ERROR_FAIL_TO_RESOLVE_NAME:
        msg = "HL_ERROR_DNS_RESOLVE_FAIL 域名解析失败";
        break;
    case HL_ERROR_INVALID_PREFIX:
        msg = "HL_ERROR_INVALID_PREFIX 无效前缀";
        break;
    case HL_ERROR_ID_OUT_OF_DATE:
        msg = "HL_ERROR_ID_OUT_OF_DATE DID过期，被加入黑名单";
        break;
    case HL_ERROR_NO_RELAY_SERVER_AVAILABLE:
        msg = "HL_ERROR_NO_RELAY_SERVER_AVAILABLE 没有可用的转发服务器";
        break;
    case HL_ERROR_INVALID_SESSION_HANDLE:
        msg = "HL_ERROR_SESSION_INVALID_HANDLE session无效";
        break;
    case HL_ERROR_SESSION_CLOSE_REMOTE:
        msg = "HL_ERROR_SESSION_REMOTE_CLOSE 对方关闭了session";
        break;
    case HL_ERROR_SESSION_CLOSE_CALLED:
        msg = "HL_ERROR_SESSION_CLOSE_CALLED 我方关闭了session";
        break;
    case HL_ERROR_SESSION_CLOSE_TIMEOUT:
        msg = "HL_ERROR_SESSION_ALIVE_TIMEOUT_CLOSE 底层⼼跳超时，需要重新连接";
        break;
    case HL_ERROR_REMOTE_SITE_BUFF_FULL:
        msg = "HL_ERROR_BUFF_FULL_REMOTE 对方接收buff满了";
        break;
    case HL_ERROR_USER_LISTEN_BREAK:
        msg = "HL_ERROR_LISTEN_BREAK 主动打断监听";
        break;
    case HL_ERROR_MAX_SESSION:
        msg = "HL_ERROR_SESSION_MAX session 超出连接数";
        break;
    case HL_ERROR_USER_CONNECT_BREAK:
        msg = "HL_ERROR_CONNECT_BREAK 主动打断连接";
        break;
    case HL_ERROR_SESSION_CLOSED_INSUFFICIENT_MEMORY:
        msg = "HL_ERROR_SESSION_CLOSED_INSUFFICIENT_MEMORY 因内存资源不足,关闭连接";
        break;
    case HL_ERROR_INVALID_LICENSE:
        msg = "HL_ERROR_INVALID_LICENSE 无效LICENSE";
        break;
    case HL_ERROR_FAIL_TO_CREATE_THREAD:
        msg = "HL_ERROR_FAIL_TO_ALLOCATE_MEMORY 创建线程失败";
        break;
    case HL_ERROR_FAIL_TO_ALLOCATE_MEMORY:
        msg = "HL_ERROR_FAIL_TO_ALLOCATE_MEMORY 内存分配失败";
        break;
    case HL_ERROR_INVALID_INIT_STRING:
        msg = "HL_ERROR_INVALID_INIT_STRING 无效加密字串";
        break;
    case HL_ERROR_BUFF_FULL_LOCAL:
        msg = "HL_ERROR_BUFF_FULL_LOCAL 我方发送buff满了";
        break;
    case HL_ERROR_BUFF_LEN:
        msg = "HL_ERROR_BUFF_LEN 读取数据的上层buff太小";
        break;
    case HL_ERROR_DATA_LEN_ZERO:
        msg = "HL_ERROR_DATA_LEN_ZERO 发送的数据必须大于0";
        break;
    case HL_ERROR_DATA_MAX_2M:
        msg = "HL_ERROR_DATA_MAX_2M 发送的数据最大不超过2M";
        break;
    case HL_ERROR_DATA_INVALID:
        msg = "HL_ERROR_DATA_INVALID 无效数据";
        break;
    case HL_ERROR_NOT_AVAILABLE:
        msg = "HL_ERROR_NOT_AVAILABLE 库没有开发该功能，请联系吕工";
        break;
    case HL_ERROR_OPEN_FILE_FAIL:
        msg = "HL_ERROR_OPEN_FILE_FAIL 打开文件失败";
        break;
    case HL_ERROR_PATH_TOO_LENGTH:
        msg = "HL_ERROR_PATH_TOO_LENGTH 文件路径太长";
        break;
    case HL_ERROR_IS_P2P_CALLBACK_DATA:
        msg = "HL_ERROR_IS_P2P_CALLBACK_DATA 你开启了p2p库回调数据，不需要你去读数据";
        break;
    case HL_ERROR_IS_P2P_LISTEN_APP_CONNECT:
        msg = "HL_ERROR_IS_P2P_CALLBACK_DATA 你开启了p2p监听APP连接，不需要你去监听连接";
        break;
    case HL_ERROR_CLOUD_DOMAIN_PARSE_FAIL:
        msg = "HL_ERROR_CLOUD_DOMAIN_PARSE_FAIL 云端服务器域名解析失败";
        break;
    case HL_ERROR_CLOUD_CONNECT_SVR_FAIL:
        msg = "HL_ERROR_CLOUD_CONNECT_SVR_FAIL 云服务器连接失败";
        break;
    case HL_ERROR_CODEC_FAIL:
        msg = "HL_ERROR_CODEC_FAIL 音视频编解码拍照录像等失败";
        break;
    case HL_ERROR_CODEC_ID_INVALID:
        msg = "HL_ERROR_CODEC_ID_INVALID cid无效";
        break;
    case HL_ERROR_CODEC_NOT_I_FRAME:
        msg = "HL_ERROR_CODEC_NOT_I_FRAME 需要i帧";
        break;
    case HL_ERROR_CODEC_DEST_BUFF_TOO_SMALL:
        msg = "HL_ERROR_CODEC_DEST_BUFF_TOO_SMALL 上层保存解码或编码后数据的buff太小(1,如果是视频,会返回当前视频的最新宽高,用于上层创建更大buff的依据；2,如果是音频,那就上层自己直接创建更大一点的buff)";
        break;
    case HL_ERROR_FAIL:
        msg = "HL_ERROR_FAIL 失败,看cb_error()回调信息";
        break;
    case HL_ERROR_MAX_SESSION_REMOTE:
        msg = "HL_ERROR_MAX_SESSION_REMOTE 对方的连接数量已满,不能再连接了";
        break;
    case HL_ERROR_CREATE_SOCKET_FAIL:
        msg = "HL_ERROR_CREATE_SOCKET_FAIL 创建socket失败,需要重启一下设备恢复";
        break;
    case HL_ERROR_DID_UNSUPPORT_WEBRTC:
        msg = "HL_ERROR_MAX_SESSION_REMOTE 这个did不支持webrtc,请使用支持webrtc的did";
        break;
    }

    char buf[1024] = {0};
    va_list args;
    va_start(args, format);
    vsprintf(buf, format, args);
    va_end(args);

    struct timeval now;
    gettimeofday(&now, NULL);

    int d = now.tv_sec % (24 * 60 * 60);
    int h = d / (60 * 60) + 8;
    int m = (d % (60 * 60)) / 60;
    int ss = now.tv_sec % 60;
    printf("[%02d:%02d:%02d.%03d] ret=%d msg=%s %s\n", h, m, ss, (int)now.tv_usec / 1000, ret, buf, msg);
}

static uint64_t _g_mst2()
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}

/**
 * 获取连接类型
 * **/
static char *_get_session_connect_status(int session)
{
    switch (session)
    {
    case HL_CONNECT_STATUS_ONLINE_LAN:
        return "局域网连接";
    case HL_CONNECT_STATUS_ONLINE_P2P:
        return "P2P连接";
    case HL_CONNECT_STATUS_ONLINE_DEV_RELAY:
        return "设备转发连接";
    case HL_CONNECT_STATUS_ONLINE_PLAT_RELAY:
        return "平台转发连接";
    case HL_CONNECT_STATUS_ONLINE_SVR_RELAY:
        return "服务器UDP转发连接";
    case HL_CONNECT_STATUS_ONLINE_SVR_RELAY_TCP:
        return "服务器TCP转发连接";
    }
    return "未知连接状态";
}

static int gSession = 0;
static void cb_log(char type, char *log)
{
    // _hl_log(1000, "cb_log() type=%d  log=%s", type, log);
}

//-------------下面是app回调-------------
// 搜索到局域网设备回调
static void cb_app_search(char *did, char end)
{
    // _hl_log(1000, "cb_app_search() did=%s end=%d", did, end);
}

// 设备端发过来透传数据回调
static void cb_app_transfer_data(char *did, int status, int qid, char *data, int data_len)
{
    _hl_log(1000, "cb_app_transfer_data() did=%s status=%d qid=%d data_len=%d", did, status, qid, data_len);
}

// 检查设备当前状态回调
static void cb_app_dev_state(char *did, char status, char mode, long end_time, long end_time_wk, char is_tcp, void *user)
{
    _hl_log(1000, "cb_app_dev_state() did=%sd status=%d mode=%d end_time=%ld end_time_wk=%ld is_tcp=%d", did, status, mode, end_time, end_time_wk, is_tcp);
}

// 连接状态回调
static void cb_app_connect_status(int session, int status, void *user)
{
    _hl_log(status, "cb_app_connect_status() sess=%d status=%d", session, status);
}

// 库主动回调数据
static void cb_app_session_data(int session, char channel, char *data, int data_len, void *user)
{
    // _hl_log(1000, "cb_app_session_data() sess=%d channel=%d data_len=%d", session, channel, data_len);
}

// 当前连接的带宽
static void cb_app_bandwidth(int session, int send_bw, int recv_bw, void *user)
{
    _hl_log(1000, "cb_app_bandwidth() sess=%d send_bw=%d recv_bw=%d", session, send_bw, recv_bw);
}

/**
 * 读取指令数据的线程,udp方式读取
 * **/
static void *_thd_read_cmd_udp(void *user_data)
{
    pthread_detach(pthread_self());

    _hl_log(1000, "_thd_read_cmd_udp()....开始 session=%d", gSession);

    // 0-表示一直不超时，直到读取到数据，或关闭session; >0表示过这么长时间后，如果没有读到数据就超时，单位是毫秒
    int timeout_ms = 0;
    // 这个值要足够大，要>=发送端发送的最大包，因为和UDP读取数据一样,如果小了，多余的数据将会被丢弃
    char *data = (char *)calloc(1, 1024);
    int data_len = 0;
    int ret = 0;
    char flag = 1;
    while (flag)
    {
        memset(data, 0, 1024);
        data_len = 1024; // 传入是：告诉底层我的buff多大，传出是：读取到了多少数据
        ret = hl_p2p_read_udp(gSession, 0, data, &data_len, timeout_ms);
        if (ret == HL_ERROR_SUCCESSFUL)
        {
            _hl_log(ret, "_thd_read_cmd_udp()....读到对方发来的命令数据 data=%s data_len=%d", data, data_len);
        }
        else if (ret == HL_ERROR_TIME_OUT)
        {
            _hl_log(ret, "_thd_read_cmd_udp()....读取超时，继续读就好");
        }
        // 读取失败，需要断开连接，等待app重新连接，上层关于这个session的资源都需要记得释放
        else if (ret < 0)
        {
            _hl_log(ret, "_thd_read_cmd_udp()....读取失败,已经断开连接了,需要重新再连接");
            break;
        }
    }

    free(data); // 释放分配的内存
    _hl_log(1000, "_thd_read_cmd_udp()....线程退出");
    return NULL;
}

/**
 * 读取指令数据的线程,tcp方式读取
 * **/
static void *_thd_read_cmd_tcp(void *user_data)
{
    pthread_detach(pthread_self());

    _hl_log(1000, "_thd_read_cmd_tcp()....开始 session=%d", gSession);

    // 0-表示一直不超时，直到读取到数据，或关闭session; >0表示过这么长时间后，如果没有读到数据就超时，单位是毫秒
    int timeout_ms = 0;
    // 这个值要足够大，要>=发送端发送的最大包，因为和UDP读取数据一样,如果小了，多余的数据将会被丢弃
    char *data = (char *)calloc(1, 1024);
    int data_len = 0;
    int ret = 0;
    char flag = 1;
    while (flag)
    {
        memset(data, 0, 1024);
        data_len = 100; // 传入表示：要读100个字节，没有读到不会出来，直到超时或者连接断开；传出表示：读到了多少数据；超时的时候很可能会读到一部分数据
        ret = hl_p2p_read_tcp(gSession, 0, data, &data_len, timeout_ms);
        if (ret == HL_ERROR_SUCCESSFUL)
        {
            _hl_log(ret, "_thd_read_cmd_tcp()....读到对方发来的命令数据 data=%s data_len=%d", data, data_len);
        }
        else if (ret == HL_ERROR_TIME_OUT)
        {
            _hl_log(ret, "_thd_read_cmd_tcp()....读取超时，继续读就好");
        }
        // 读取失败，需要断开连接，等待app重新连接，上层关于这个session的资源都需要记得释放
        else if (ret < 0)
        {
            _hl_log(ret, "_thd_read_cmd_tcp()....读取失败,已经断开连接了,需要重新再连接");
            break;
        }
    }

    free(data); // 释放分配的内存
    _hl_log(1000, "_thd_read_cmd_tcp()....线程退出");
    return NULL;
}

/**
 * 从通道1读取大数据,udp方式读取
 * **/
static void *_thd_read_data_udp(void *user_data)
{
    pthread_detach(pthread_self());

    _hl_log(1000, "_thd_read_data_udp()....开始 session=%d", gSession);

    // 0-表示一直不超时，直到读取到数据，或关闭session; >0表示过这么长时间后，如果没有读到数据就超时，单位是毫秒
    int timeout_ms = 0;
    // 这个值要足够大，要>=发送端发送的最大包，因为和UDP读取数据一样,如果小了，多余的数据将会被丢弃
    char *data = (char *)calloc(1, 1025);
    int data_len = 0;
    int ret = 0, sum = 0;

    char flag = 1;
    while (flag)
    {
        data_len = 1024; // 传入是：告诉底层我的buff多大，传出是：读取到了多少数据
        ret = hl_p2p_read_udp(gSession, 1, data, &data_len, timeout_ms);
        if (ret == HL_ERROR_SUCCESSFUL)
        {
            sum += data_len;
            _hl_log(ret, "_thd_read_data_udp()....读到对方发来的数据 sum=%d data_len=%d", sum, data_len);
        }
        else if (ret == HL_ERROR_TIME_OUT)
        {
            _hl_log(ret, "_thd_read_data_udp()....读取超时，继续读就好");
        }
        // 读取失败，需要断开连接，等待app重新连接，上层关于这个session的资源都需要记得释放
        else if (ret < 0)
        {
            _hl_log(ret, "_thd_read_data_udp()....读取失败,已经断开连接了,需要重新再连接");
            break;
        }
    }

    free(data); // 释放分配的内存
    _hl_log(1000, "_thd_read_data_udp()....线程退出");
    return NULL;
}

/**
 * 通过通道1，向对方发送大数据
 * **/
static void *_thd_send_data(void *user_data)
{
    pthread_detach(pthread_self());

    _hl_log(1000, "_thd_send_data()....开始 session=%d", gSession);

    /**
     * 注意：
     * 1）发送大数据一般不加密，库里面采用AES对称加密，对大数据加密浪费cpu
     * 2）如果一定要加密，建议上层对数据头进行加密，或采用其他策略
     * 3）音视频数据一帧可以一次write不需要拆分视频帧,除非一帧大于2M数据
     * **/
    char *data = (char *)calloc(1, 1024);
    int ret = 0, read_len = 0, write_len = 0;
    int total = 512 * 1024, sum = 0; // 要发送的数据
    char f = 1, flag = 1;
    while (sum < total && f)
    {
        // 1.检查对应通道本地缓存还有多少
        flag = 1;
        while (flag)
        {
            ret = hl_p2p_check_buffer(gSession, 1, &read_len, &write_len);
            // 该通道底层还有很多数据没有发送出去，可能网络有点慢，需要延时一下
            if (ret == HL_ERROR_BUFF_FULL_LOCAL || (ret == HL_ERROR_SUCCESSFUL && write_len > (256 * 1024)))
                usleep(10 * 1000); /***需要延时，延时10ms**/
            else if (ret < 0)
            {
                flag = 0;
                f = 0;
                _hl_log(ret, "_thd_send_data()...连接出现问题了，需要断开重连");
                break;
            }
            else
                flag = 0; // 结束延时，可以发数据了
        }

        // 2.向对方发送数据
        ret = hl_p2p_write(gSession, 1, data, 1024, 0);
        if (ret > 0)
        {
            sum += ret;
            _hl_log(ret, "_thd_send_data()...数据发送成功 %d%%", sum * 100 / total);
        }
        else if (ret == HL_ERROR_BUFF_FULL_LOCAL)
        {
            _hl_log(ret, "_thd_send_data()...这一帧发送失败，因为本地缓存已经满了，两种处理方案：1）丢掉这帧，2）延时10ms再次重发这一帧 直到发送成功");
        }
        else if (ret < 0)
        {
            flag = 0;
            f = 0;
            _hl_log(ret, "_thd_send_data()...连接出现问题了，需要断开重连");
        }
    }

    if (total == sum)
        _hl_log(ret, "_thd_send_data()...所有数据都发送完成 total=%d sum=%d", total, sum);

    free(data); // 释放分配的内存
    _hl_log(1000, "qwe..._thd_read_cmd_tcp()....线程退出");
    return NULL;
}

//------使用哈喽函数-------
int hl_init()
{
    // 0.获取库版本号
    _hl_log(1000, "库版本号=%d", hl_p2p_get_version());

    // 1.设置回调，要在初始化库前
    hl_p2p_cb cb;
    bzero(&cb, sizeof(cb));
    cb.cb_log = &cb_log;
    // app端回调
    cb.cb_app_search = &cb_app_search;
    cb.cb_app_transfer_data = &cb_app_transfer_data;
    cb.cb_app_dev_state = &cb_app_dev_state;
    cb.cb_app_connect_status = &cb_app_connect_status;
    cb.cb_app_session_data = &cb_app_session_data;
    cb.cb_app_bandwidth = &cb_app_bandwidth;

    hl_p2p_set_callback(&cb);

    // 2.开启库日志,开启会有比多日志
    hl_p2p_set_log_level(HL_LOG_TYPE_MGT | HL_LOG_TYPE_SESS | HL_LOG_TYPE_CGT | HL_LOG_TYPE_WEBRTC, 0, 1);

    // 3.初始化库
    // 加密字串
    char *svr = "DAS-2E97A741893A5D8FF6F425C8116F5588CFA1226897E93466A75449C895E09D71C815B958DDBD7F771C9A6F0C112F7996F985834F9DD5DCCE7A7A64A86BAEF0FF21F3C04456921E7F13E961B4EEAFB8E15C27341A076DB83512880DA86BB46DF0C525211150ADFF6BA4408C7C5FEFF702";

    /**
     * 下面的参数可以 自己修改做相应的测试
     * 推荐：使用库监听和库回调数据
     * **/
    int session_max = 255;         // 同时支持多少个app连接
    char channel_max = 8;          // 每个连接有多少个通道数
    char session_alive_sec = 10;   // 连接之间的心跳超时时间
    char is_lib_callback_data = 1; // 是否库主动回调数据，0-不回调主动去读，1-回调不需要去读
    char is_one_svr_alive = 0;     // 作为设备端时，是否只向一个服务器保持心跳，减少服务器带宽压力，增加服务器支持设备的数量：0-向多个服务器保持心跳，1-只向其中一台保持心跳
    int ret = hl_p2p_init(svr, session_max, channel_max, session_alive_sec, is_lib_callback_data, is_one_svr_alive);
    if (ret != HL_ERROR_SUCCESSFUL)
    {
        _hl_log(ret, "");
        return 0;
    }

    // 4.搜索局域网设备，在cb_app_search()回调函数返回结果
    ret = hl_p2p_search_lan();
    _hl_log(ret, "");

    // 设备ID
    char *did = "HIXX00000036KPMJH";

    // 5.查询设备当前状态
    // a.同步查询状态
    // hl_dev_state dev = {0};
    // hl_p2p_check_dev_state(did, svr, &dev);
    // // b.异步查询设备状态,在cb_app_dev_state()回调里面返回结果
    // hl_p2p_check_dev_state_async(did, svr, 10, NULL);

    // 6.向设备发透传消息,不需要连接设备,主要用在发送少量指令数据,因为该数据通过p2p服务器转发,大数据会增加服务器带宽压力
    // char *data = "this is app transfer data";
    // int reqid = 12; // 上层自己定义的唯一ID,用于结果校验，结果在cb_app_transfer_data()回调
    // hl_p2p_transfer_data(did, svr, reqid, data, strlen(data));

    // 7.连接设备
    /**
     * 连接模式：
     * 1）长电WiFi/4G(非定向卡)，采用：HL_CONNECT_MODE_ALL
     * 2）低功耗WiFi/4G(非定向卡)，采用：HL_CONNECT_MODE_FAST
     * 3）4G定向卡设备，采用：HL_CONNECT_MODE_SRELAY_ONLY
     * 4）其他模式自己测试
     *
     * **/
    char cmode = HL_CONNECT_MODE_ALL;
    /**
     * 只有连接低功耗设备时，才使用这个数据
     * 这个是向设备发起唤醒时，把这个数据带在唤醒指令最后面
     * 让设备提前收到一些数据
     * **/
    char *wakeup = NULL;
    char wakeup_len = 0;
    /**
     * 这个主要用在回调上面，
     * 上层比如封装了一个连接对象，把对象传给库，回调时库把对象回调回来
     * 方便上层使用，这个和使用线程的user_data一样
     *
     * 注意：上层如果已经释放了这个对象，回调回来如何还去使用该对象就会崩溃，需要注意该bug
     *
     * **/
    void *user = NULL;

    // 采用下面其中一种方式连接设备，推荐使用带svr的
    //  a.同步连接设备,使用初始化时的加密字串
    // gSession = hl_p2p_connect_async(did, cmode, wakeup, wakeup_len, user);
    // // b.同步连接设备,使用指定加密字串(推荐使用：当设备量大量增加时，会架设更多的服务器集群，一个加密字串对应一个服务器集群)
    // gSession = hl_p2p_connect_by_server_async(did, cmode, svr, wakeup, wakeup_len, user);
    // // c.异步连接设备,使用初始化时的加密字串
    // gSession= hl_p2p_connect(did, cmode, wakeup, wakeup_len);
    // d.异步连接设备,使用指定加密字串(推荐使用：当设备量大量增加时，会架设更多的服务器集群，一个加密字串对应一个服务器集群)
    uint64_t now = _g_mst2();
    gSession = hl_p2p_connect_by_server(did, cmode, svr, wakeup, wakeup_len);
    if (gSession > 0)
    {
        _hl_log(gSession, "连接成功 sess=%d 耗时=%lldms", gSession, _g_mst2() - now);
    }
    else
    {
        _hl_log(gSession, "连接失败 耗时=%lldms", _g_mst2() - now);
        return 0;
    }

    // 8.在同步连接未结束，但是又想提前结束连接，调用该函数
    // hl_p2p_connect_break();

    // 9.检查这次连接的状态类型
    int status = hl_p2p_check(gSession);
    _hl_log(status, "连接状态=%s", _get_session_connect_status(status));

    /***
     * 10.读取命令通道数据
     *
     * 注意：如果设置了库回调数据，则不需要读取数据
     * **/
    // pthread_t tid;
    // pthread_create(&tid, NULL, _thd_read_cmd_udp, NULL); // 按照udp方式读取

    // pthread_create(&tid, NULL, _thd_read_cmd_tcp, NULL);//按照tcp发送读取

    // 11.读数据还没有到超时时间 想结束读数据的线程,调用该函数读的函数会马上返回,需要提前把现在循环标志设置成0
    //  hl_p2p_read_break(gSession,0);

    // 12.开线程从通道1读大数据
    // pthread_create(&tid, NULL, _thd_read_data_udp, NULL); // 按照udp方式读取

    /**
     * 13.向对方发送数据
     * a）命令数据直接发送
     * b）大数据发送前需要调用hl_p2p_check_buffer()函数，大数据：音视频数据/文件数据/其他需要进行大量发送的数据
     * **/

    // 发送命令数据，使用0通道发送指令数据，0通道默认是加密的
    // char *data = "app send cmd";
    // ret = hl_p2p_write(gSession, 0, data, strlen(data), 1);
    // if (ret < 0)
    // {
    //     _hl_log(ret, "发送数据失败");
    //     return 0;
    // }

    // 开线程向通道1发送大数据
    // pthread_create(&tid, NULL, _thd_send_data, NULL);

    // 14.清空库中对应通道的数据
    // hl_p2p_clear_buffer(gSession, 0, 1);

    // 15.断开与对方的连接
    // hl_p2p_close(gSession);
    // hl_p2p_force_close(gSession);

    // 16.注销库
    // hl_p2p_deinit();

    return 1;
}
